/*
 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package javax.xml.ws.spi.http;

import javax.xml.ws.handler.MessageContext;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.security.Principal;

/**
 * This class encapsulates a HTTP request received and a
 * response to be generated in one exchange. It provides methods
 * for examining the request from the client, and for building and
 * sending the response.
 * <p>
 * A <code>HttpExchange</code> must be closed to free or reuse
 * underlying resources. The effect of failing to close an exchange
 * is undefined.
 *
 * @author Jitendra Kotamraju
 * @since JAX-WS 2.2
 */
public abstract class HttpExchange {

  /**
   * Standard property: cipher suite value when the request is received
   * over HTTPS
   * <p>Type: String
   */
  public static final String REQUEST_CIPHER_SUITE =
      "javax.xml.ws.spi.http.request.cipher.suite";

  /**
   * Standard property: bit size of the algorithm when the request is
   * received over HTTPS
   * <p>Type: Integer
   */
  public static final String REQUEST_KEY_SIZE =
      "javax.xml.ws.spi.http.request.key.size";

  /**
   * Standard property: A SSL certificate, if any, associated with the request
   *
   * <p>Type: java.security.cert.X509Certificate[]
   * The order of this array is defined as being in ascending order of trust.
   * The first certificate in the chain is the one set by the client, the next
   * is the one used to authenticate the first, and so on.
   */
  public static final String REQUEST_X509CERTIFICATE =
      "javax.xml.ws.spi.http.request.cert.X509Certificate";

  /**
   * Returns an immutable Map containing the HTTP headers that were
   * included with this request. The keys in this Map will be the header
   * names, while the values will be a List of Strings containing each value
   * that was included (either for a header that was listed several times,
   * or one that accepts a comma-delimited list of values on a single line).
   * In either of these cases, the values for the header name will be
   * presented in the order that they were included in the request.
   * <p>
   * The keys in Map are case-insensitive.
   *
   * @return an immutable Map which can be used to access request headers
   */
  public abstract Map<String, List<String>> getRequestHeaders();

  /**
   * Returns the value of the specified request header. If the request
   * did not include a header of the specified name, this method returns
   * null. If there are multiple headers with the same name, this method
   * returns the first header in the request. The header name is
   * case-insensitive. This is a convienence method to get a header
   * (instead of using the {@link #getRequestHeaders}).
   *
   * @param name the name of the request header
   * @return returns the value of the requested header, or null if the request does not have a
   * header of that name
   */
  public abstract String getRequestHeader(String name);

  /**
   * Returns a mutable Map into which the HTTP response headers can be stored
   * and which will be transmitted as part of this response. The keys in the
   * Map will be the header names, while the values must be a List of Strings
   * containing each value that should be included multiple times
   * (in the order that they should be included).
   * <p>
   * The keys in Map are case-insensitive.
   *
   * @return a mutable Map which can be used to set response headers.
   */
  public abstract Map<String, List<String>> getResponseHeaders();

  /**
   * Adds a response header with the given name and value. This method
   * allows a response header to have multiple values. This is a
   * convenience method to add a response header(instead of using the
   * {@link #getResponseHeaders()}).
   *
   * @param name the name of the header
   * @param value the additional header value. If it contains octet string, it should be encoded
   * according to RFC 2047 (http://www.ietf.org/rfc/rfc2047.txt)
   * @see #getResponseHeaders
   */
  public abstract void addResponseHeader(String name, String value);

  /**
   * Returns the part of the request's URI from the protocol
   * name up to the query string in the first line of the HTTP request.
   * Container doesn't decode this string.
   *
   * @return the request URI
   */
  public abstract String getRequestURI();

  /**
   * Returns the context path of all the endpoints in an application.
   * This path is the portion of the request URI that indicates the
   * context of the request. The context path always comes first in a
   * request URI. The path starts with a "/" character but does not
   * end with a "/" character. If this method returns "", the request
   * is for default context. The container does not decode this string.
   *
   * <p>
   * Context path is used in computing the endpoint address. See
   * {@link HttpContext#getPath}
   *
   * @return context path of all the endpoints in an application
   * @see HttpContext#getPath
   */
  public abstract String getContextPath();

  /**
   * Get the HTTP request method
   *
   * @return the request method
   */
  public abstract String getRequestMethod();

  /**
   * Returns a {@link HttpContext} for this exchange.
   * Container matches the request with the associated Endpoint's HttpContext
   *
   * @return the HttpContext for this exchange
   */
  public abstract HttpContext getHttpContext();

  /**
   * This must be called to end an exchange. Container takes care of
   * closing request and response streams. This must be called so that
   * the container can free or reuse underlying resources.
   *
   * @throws IOException if any i/o error
   */
  public abstract void close() throws IOException;

  /**
   * Returns a stream from which the request body can be read.
   * Multiple calls to this method will return the same stream.
   *
   * @return the stream from which the request body can be read.
   * @throws IOException if any i/o error during request processing
   */
  public abstract InputStream getRequestBody() throws IOException;

  /**
   * Returns a stream to which the response body must be
   * written. {@link #setStatus}) must be called prior to calling
   * this method. Multiple calls to this method (for the same exchange)
   * will return the same stream.
   *
   * @return the stream to which the response body is written
   * @throws IOException if any i/o error during response processing
   */
  public abstract OutputStream getResponseBody() throws IOException;

  /**
   * Sets the HTTP status code for the response.
   *
   * <p>
   * This method must be called prior to calling {@link #getResponseBody}.
   *
   * @param status the response code to send
   * @see #getResponseBody
   */
  public abstract void setStatus(int status);

  /**
   * Returns the unresolved address of the remote entity invoking
   * this request.
   *
   * @return the InetSocketAddress of the caller
   */
  public abstract InetSocketAddress getRemoteAddress();

  /**
   * Returns the unresolved local address on which the request was received.
   *
   * @return the InetSocketAddress of the local interface
   */
  public abstract InetSocketAddress getLocalAddress();

  /**
   * Returns the protocol string from the request in the form
   * <i>protocol/majorVersion.minorVersion</i>. For example,
   * "HTTP/1.1"
   *
   * @return the protocol string from the request
   */
  public abstract String getProtocol();

  /**
   * Returns the name of the scheme used to make this request,
   * for example: http, or https.
   *
   * @return name of the scheme used to make this request
   */
  public abstract String getScheme();

  /**
   * Returns the extra path information that follows the web service
   * path but precedes the query string in the request URI and will start
   * with a "/" character.
   *
   * <p>
   * This can be used for {@link MessageContext#PATH_INFO}
   *
   * @return decoded extra path information of web service. It is the path that comes after the web
   * service path but before the query string in the request URI <tt>null</tt> if there is no extra
   * path in the request URI
   */
  public abstract String getPathInfo();

  /**
   * Returns the query string that is contained in the request URI
   * after the path.
   *
   * <p>
   * This can be used for {@link MessageContext#QUERY_STRING}
   *
   * @return undecoded query string of request URI, or <tt>null</tt> if the request URI doesn't have
   * one
   */
  public abstract String getQueryString();

  /**
   * Returns an attribute that is associated with this
   * <code>HttpExchange</code>. JAX-WS handlers and endpoints may then
   * access the attribute via {@link MessageContext}.
   * <p>
   * Servlet containers must expose {@link MessageContext#SERVLET_CONTEXT},
   * {@link MessageContext#SERVLET_REQUEST}, and
   * {@link MessageContext#SERVLET_RESPONSE}
   * as attributes.
   *
   * <p>If the request has been received by the container using HTTPS, the
   * following information must be exposed as attributes. These attributes
   * are {@link #REQUEST_CIPHER_SUITE}, and {@link #REQUEST_KEY_SIZE}.
   * If there is a SSL certificate associated with the request, it must
   * be exposed using {@link #REQUEST_X509CERTIFICATE}
   *
   * @param name attribute name
   * @return the attribute value, or <tt>null</tt> if the attribute doesn't exist
   */
  public abstract Object getAttribute(String name);

  /**
   * Gives all the attribute names that are associated with
   * this <code>HttpExchange</code>.
   *
   * @return set of all attribute names
   * @see #getAttribute(String)
   */
  public abstract Set<String> getAttributeNames();

  /**
   * Returns the {@link Principal} that represents the authenticated
   * user for this <code>HttpExchange</code>.
   *
   * @return Principal for an authenticated user, or <tt>null</tt> if not authenticated
   */
  public abstract Principal getUserPrincipal();

  /**
   * Indicates whether an authenticated user is included in the specified
   * logical "role".
   *
   * @param role specifies the name of the role
   * @return <tt>true</tt> if the user making this request belongs to a given role
   */
  public abstract boolean isUserInRole(String role);

}
